<template>
  <el-dialog :title="dialogTitle" v-model="visible" append-to-body :width="dialogWidth" destroy-on-close :close-on-click-modal="false">
    <el-row class="search__wrap" v-if="showSearchWrap">
      <el-collapse style="width: 100%">
        <el-collapse-item title="展开搜索栏" name="1">
          <div class="input__wrap">
            <div class="input__item" v-for="(node, index) in inputNodeList" :key="index">
              <el-form-item :label="node.label + ' :'">
                <el-input v-model.trim="search[node.field]" clearable></el-input>
              </el-form-item>
            </div>
          </div>
          <el-row class="control__wrap" justify="end">
            <el-button @click="onReset">重置</el-button>
            <el-button type="primary" @click="onSearch">搜索</el-button>
          </el-row>
        </el-collapse-item>
      </el-collapse>
    </el-row>
    <div class="select__list" v-loading="loading">
      <el-transfer v-bind="transferProps" class="select-transfer__wrap" v-model="jdValue" :data="jdData">
        <template #left-footer>
          <slot name="left-footer"></slot>
        </template>

        <template #right-footer>
          <slot name="right-footer"></slot>
        </template>
      </el-transfer>
    </div>
    <template #footer>
      <div class="control__wrap">
        <el-button @click="close">取消</el-button>
        <el-button @click="confirm" type="primary">确定</el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script>
export default {
  name: "developer",
  emits: ["update:modelValue"],
  props: {
    dialogWidth: { type: String, default: "" },
    dialogTitle: { type: String, default: "标题" },
    apiObj: { type: Object, default: () => {} },
    hideSearch: { type: Boolean, default: false },
    inputNodeList: { type: Array, default: () => [] },
    modelValue: { type: Array, default: () => [] },
    // 此属性是配合renderContent属性使用
    generateData: { type: Function, default: null },
    // 以下是el-transfer属性
    data: { type: Array, default: () => [] },
    titles: { type: Array, default: () => ["List 1", "List 2"] },
    filterPlaceholder: { type: String, default: "Enter keyword" },
    targetOrder: { type: String, default: "original" },
    buttonTexts: { type: Array, default: () => [] },
    leftDefaultChecked: { type: Array, default: () => [] },
    rightDefaultChecked: { type: Array, default: () => [] },
    // 这里的值需要判断，因为没有默认值,或是boolean
    filterable: { type: Boolean, default: false },
    validateEvent: { type: Boolean, default: true },
    format: { type: Object, default: null },
    filterMethod: { type: Function, default: null },
    renderContent: { type: Function, default: null },
    props: { type: Object, default: null }
  },
  computed: {
    transferProps() {
      const result = {
        titles: this.titles,
        filterPlaceholder: this.filterPlaceholder,
        targetOrder: this.targetOrder,
        buttonTexts: this.buttonTexts,
        leftDefaultChecked: this.leftDefaultChecked,
        rightDefaultChecked: this.rightDefaultChecked
      }

      !!this.validateEvent && (result.validateEvent = !!this.validateEvent)
      !!this.filterable && (result.filterable = !!this.filterable)
      !!this.format && (result.format = this.format)
      !!this.filterMethod && (result.filterMethod = this.filterMethod)
      !!this.renderContent && (result.renderContent = this.renderContent)
      !!this.props && (result.props = this.props)

      return result
    },
    showSearchWrap() {
      return !this.hideSearch && this.inputNodeList.length > 0
    }
  },
  watch: {
    modelValue: {
      handler(val) {
        let result = []
        let valueKey = "key"
        !!this.props && (valueKey = this.props.key)
        if (Array.isArray(val)) {
          if (this.jdData.length > 0) {
            const cacheJdData = []
            val.forEach((value) => {
              result.push(value[valueKey])
              cacheJdData.push([value[valueKey], value])
            })
            const tmpRes = this.jdData.map((item) => [item[valueKey], item])
            const jdData = new Map([...cacheJdData, ...tmpRes])
            this.jdData = [...jdData.values()]
          } else {
            this.jdData = val
            val.forEach((value) => {
              let valueKey = "key"
              !!this.props && (valueKey = this.props.key)
              result.push(value[valueKey])
            })
          }
        }
        this.jdValue = result
      },
      deep: true,
      immediate: true
    },
    inputNodeList: {
      handler(val) {
        val.forEach((node) => {
          this.serach[node.field] = node.value
        })
      },
      deep: true
    }
  },
  data() {
    return {
      visible: false,
      jdValue: [],
      jdData: [],
      search: {},
      isSearch: false,
      loading: false
    }
  },
  methods: {
    async getData() {
      this.loading = true
      if (this.apiObj) {
        const res = await this.apiObj.get(this.serach)
        this.generateData ? (this.jdData = this.generateData(res.data.rows)) : (this.jdData = res.data.rows)
      } else {
        this.generateData ? (this.jdData = this.generateData(this.data)) : (this.jdData = this.data)
      }
      this.loading = false
    },
    onReset() {
      // 如果所有的input都是空的,直接返回,不刷新
      // 否则清空input,重新请求
      if (Object.values(this.search).length == 0) return
      Object.keys(this.search).forEach((key) => {
        this.search[key] = ""
      })
      this.getData()
    },
    // 因为搜索会更新左侧框的数据同时影响右侧框的显示
    // 需求: 左侧框更新数据,右侧显示已添加的所有的对象
    // 目前解决方案是通过右侧框的值去索引,将左侧框更新的数据进行缓存,并添加到更新后的数据中进行去重
    onSearch() {
      if (Object.values(this.search).length == 0) return
      // 因为transfer的props的key可能有被修改,因此需做判断
      let valueKey = "key"
      !!this.props && (valueKey = this.props.key)

      // 获取左侧缓存数据,并处理数据格式,处理为符合转为Map的Array结构
      const cacheJdData = []
      this.jdValue.forEach((value) => {
        const tmpItem = this.jdData.find((item) => item[valueKey] == value)
        cacheJdData.push([tmpItem[valueKey], tmpItem])
      })

      // 获取左侧更新数据
      // const res = [
      //   {
      //     memberId: 123,
      //     nickName: 123,
      //     disabled: false,
      //     avatar: undefined,
      //     item: {}
      //   }
      // ]
      const res = this.getData()
      // 处理为符合转为Map的Array结构
      const tmpRes = res.map((item) => [item[valueKey], item])
      // 合并去重
      const jdData = new Map([...cacheJdData, ...tmpRes])
      // 更新jdData
      this.jdData = [...jdData.values()]
    },
    open() {
      this.getData()
      this.visible = true
    },
    close() {
      this.visible = false
    },
    confirm() {
      const result = []
      let valueKey = "key"
      !!this.props && (valueKey = this.props.key)
      this.jdValue.forEach((value) => {
        const tmpItem = this.jdData.find((item) => item[valueKey] == value)
        result.push(tmpItem)
      })
      this.$emit("update:modelValue", result)
      this.visible = false
    }
  }
}
</script>

<style lang="scss">
.search__wrap {
  margin-bottom: 30px;
  gap: 10px;
  .input__wrap {
    margin-right: -30px;
    margin-top: 15px;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    .input__item {
      padding-right: 30px;
      margin-bottom: 15px;
      width: 33.3%;
      box-sizing: border-box;
    }
    .el-form-item {
      margin-bottom: 0;
      .el-form-item__label {
        padding-right: 6px;
        font-size: 12px;
      }
    }
  }
  .el-collapse-item__header {
    font-size: 15px;
    color: #606266;
  }
  .el-collapse-item__content {
    padding-bottom: 15px;
  }
  .control__wrap {
    width: 100%;
  }
}
.select__list {
  display: flex;
  justify-content: center;
  .el-dialog__body {
    padding-left: 0;
    padding-right: 0;
  }
  .select-transfer__wrap {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
}
</style>
